package org.x4444.mywsgwt.client;

import java.util.Date;

import net.zschech.gwt.websockets.client.CloseHandler;
import net.zschech.gwt.websockets.client.ErrorHandler;
import net.zschech.gwt.websockets.client.MessageEvent;
import net.zschech.gwt.websockets.client.MessageHandler;
import net.zschech.gwt.websockets.client.OpenHandler;
import net.zschech.gwt.websockets.client.WebSocket;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;

public class MyWsGwt implements EntryPoint {

	private WebSocket webSocket;

	private HTML messages;
	private ScrollPanel scrollPanel;

	private TextBox url;
	private TextBox input;

	private Button connect;
	private Button disconnect;
	private Button send;
	Label sendTime;
	
	boolean isConnected;
	
	// in ms
	public static final int TIMEOUT = 61000;

	@Override
	public void onModuleLoad() {

		url = new TextBox();
		url.setWidth("450px");
		url.setValue("ws://greensoft.gotdns.com:18080/myws/myws");
		input = new TextBox();
		input.setWidth("450px");
		sendTime = new Label();

		connect = new Button("Connect", new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				connect();
			}
		});
		
		url.addKeyPressHandler(new KeyPressHandler() {
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					connect();
				}
			}
		});
		
		disconnect = new Button("Disconnect", new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				webSocket.close();
			}
		});
		send = new Button("Send", new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				sendMessage(input.getValue(), true, true);
			}
		});
		
		input.addKeyPressHandler(new KeyPressHandler() {
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					sendMessage(input.getValue(), true, true);
				}
			}
		});

		messages = new HTML();
		scrollPanel = new ScrollPanel();
		scrollPanel.setHeight("400px");
		scrollPanel.add(messages);

		FlowPanel controls = new FlowPanel();
		controls.add(url);
		controls.add(connect);
		controls.add(disconnect);
		RootPanel.get().add(controls);

		RootPanel.get().add(scrollPanel);

		controls = new FlowPanel();
		controls.add(input);
		controls.add(send);
		controls.add(sendTime);
		RootPanel.get().add(controls);
	}

	void sendMessage(String msg, boolean cleanInput, boolean resetTimer) {
		DateTimeFormat dtf = DateTimeFormat.getFormat("HH:mm:ss.SSS");
		String time = dtf.format(new Date());
		sendTime.setText(time);
		webSocket.send(msg);
		if (cleanInput) {
			input.setValue("");
		}
		if (resetTimer) {
			resetTimer();
		}
	}

	public void connect() {
		if (isConnected) {
			Window.alert("Already connected");
			return;
		}
		try {
			webSocket = WebSocket.create(url.getValue());
			webSocket.setOnOpen(new OpenHandler() {
				@Override
				public void onOpen(WebSocket webSocket) {
					isConnected = true;
					output("open", "silver");
					resetTimer();
				}
			});
			webSocket.setOnClose(new CloseHandler() {
				@Override
				public void onClose(WebSocket webSocket) {
					isConnected = false;
					output("close", "silver");
					hbTimer.cancel();
				}
			});
			webSocket.setOnError(new ErrorHandler() {
				@Override
				public void onError(WebSocket webSocket) {
					output("error", "red");
				}
			});
			webSocket.setOnMessage(new MessageHandler() {
				@Override
				public void onMessage(WebSocket webSocket, MessageEvent event) {
					output(event.getData(), "black");
				}
			});
			isConnected = true;
		} catch (JavaScriptException e) {
			output(e.toString(), "red");
		}
	}

	public void output(String text, String color) {
		DivElement div = Document.get().createDivElement();
		DateTimeFormat dtf = DateTimeFormat.getFormat("HH:mm:ss.SSS");
		String time = dtf.format(new Date());
		div.setInnerText(time + " " + text);
		div.setAttribute("style", "color:" + color);
		messages.getElement().appendChild(div);
		scrollPanel.scrollToBottom();
	}
	
	Timer hbTimer = new Timer() {
		
		@Override
		public void run() {
			sendMessage("hb", false, false);
		}
	};
	
	void resetTimer() {
		hbTimer.cancel();
		hbTimer.scheduleRepeating(TIMEOUT - 1000);
	}
}